简介

(初稿)
Android NDK开发属于Android开发中的高阶内容,其不仅要熟悉Android平台知识,更需要熟悉C++语言和相关的构建工具。而NDK开发中出现的异常是Android APP crash的主要原因。NDK开发的异常调试和分析比较困难,日志信息可读性很差。因此本文对NDK开发中常用的工具和方法进行总结,以期能帮助大家提升Android NDK开发的水平。

首先,关于JNI和Android NDK开发,请务必先认真完成以下文章的阅读:

Android NDK的调试和分析主要有以下几种方法:

  1. LLDB:原生调试,支持断点和变量查看,用于开发者有源码的情况下,多用于开发阶段;
  2. ndk-gdb:支持ndk-build脚本构建的工程,当前Android studio默认已采用CMake方式构建工程,所以不是很推荐;
  3. ndk-stack:适用于已经发布版本,或者用户反馈问题(提供了错误logcat日志)等情况,即直接分析NDK错误日志,分析C++源码的错误点。
  4. AddressSanitize:google官方提供的用于检测C/C++代码的memory error的工具(除了Android,其他平台也可以使用)。
  5. Native Tracing:对C++代码进行跟踪分析,比如执行时间和效率等等。使用非常简单,仅需要依赖Android的#include <android/trace.h>头文件即可。但仅在Android API Level>=23才支持。用于在开发阶段优化代码逻辑,提升算法质量等。

Note:推荐采用LLDB或ndk-stack

LLDB

请参见https://developer.android.com/studio/debug/

ndk-gdb

请参见https://developer.android.com/ndk/guides/ndk-gdb

ndk-stack

请参见https://developer.android.com/ndk/guides/ndk-stack

使用命令格式如下(其中,$NDK代表NDK的安装目录,新版Android studio的SDK Manager会将NDK安装在Android SDK目录下的ndk-bundle子目录,如果是自己单独下载NDK的话,请找到对应的解压路径。新版Android studio采用CMake构建,构建生成的so文件位于$PROJECT_PATH/app/build/intermediates/cmake/debug/obj/<abi>下(debug模式)或$PROJECT_PATH/app/build/intermediates/cmake/debug/release/<abi>(release模式),其中 <abi> 表示您的设备的ABI)。当然也可以直接从Android APK解压提取共享库so文件,然后存放在指定目录,以便分析。

adb logcat | $NDK/ndk-stack -sym $PROJECT_PATH/app/build/intermediates/cmake/debug/obj/<abi>

或者分开执行:

adb  logcat   > /tmp/foo.txt
$NDK/ndk-stack  -sym   $PROJECT_PATH/app/build/intermediates/cmake/debug/obj/<abi>   -dump   foo.txt

示例(以windows为例):

cd F:\ubuntu\share\V8Android\app\build\intermediates\cmake\debug\obj\arm64-v8a
“F:\Android\sdk\ndk-bundle\ndk-stack.cmd”  -sym  .  -dump  D:\UserProfiles\CoulsonChen\Desktop\ndk.txt   >analyze.txt

analyze.txt的内容如下(从中可以明确看到出错的代码行在哪里):

********** Crash dump: **********
Build fingerprint: 'google/walleye/walleye:8.1.0/OPM1.171019.019/4527419:user/release-keys'
pid: 6740, tid: 6740, name: boyaa.v8wrapper  >>> com.boyaa.v8wrapper <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x27
Stack frame         #00 pc 000000000056f204  /data/app/com.boyaa.v8wrapper-gc82kSUIyk_jPb6OjAZERw==/lib/arm64/libnative-lib.so: Routine v8::base::Relaxed_Load(long const volatile*) at /home/ibon/v8/v8/out.gn/aar_lkgr_64/../../src/base/atomicops_internals_portable.h:168
Stack frame         #01 pc 000000000056df00  /data/app/com.boyaa.v8wrapper-gc82kSUIyk_jPb6OjAZERw==/lib/arm64/libnative-lib.so: Routine v8::internal::(anonymous namespace)::InstantiateObject(v8::internal::Isolate*, v8::internal::Handle<v8::internal::ObjectTemplateInfo>, v8::internal::Handle<v8::internal::JSReceiver>, bool, bool) at /home/ibon/v8/v8/out.gn/aar_lkgr_64/../../src/api-natives.cc:375
Stack frame         #02 pc 000000000056ddc4  /data/app/com.boyaa.v8wrapper-gc82kSUIyk_jPb6OjAZERw==/lib/arm64/libnative-lib.so: Routine v8::internal::ApiNatives::InstantiateObject(v8::internal::Handle<v8::internal::ObjectTemplateInfo>, v8::internal::Handle<v8::internal::JSReceiver>) at /home/ibon/v8/v8/out.gn/aar_lkgr_64/../../src/api-natives.cc:547
Stack frame         #03 pc 00000000000f4774  /data/app/com.boyaa.v8wrapper-gc82kSUIyk_jPb6OjAZERw==/lib/arm64/libnative-lib.so: Routine v8::ObjectTemplate::NewInstance(v8::Local<v8::Context>) at /home/ibon/v8/v8/out.gn/aar_lkgr_64/../../src/api.cc:6733 (discriminator 2)
Stack frame         #04 pc 00000000000cfa40  /data/app/com.boyaa.v8wrapper-gc82kSUIyk_jPb6OjAZERw==/lib/arm64/libnative-lib.so (WrapGamerObject(v8::Isolate*, Gamer*)+588): Routine WrapGamerObject(v8::Isolate*, Gamer*) at F:\ubuntu\share\V8Android\app\src\main\cpp/util.cpp:208
Stack frame         #05 pc 00000000000d22cc  /data/app/com.boyaa.v8wrapper-gc82kSUIyk_jPb6OjAZERw==/lib/arm64/libnative-lib.so (initV8()+792): Routine initV8() at F:\ubuntu\share\V8Android\app\src\main\cpp/native-lib.cpp:67
Stack frame         #06 pc 00000000000d35d0  /data/app/com.boyaa.v8wrapper-gc82kSUIyk_jPb6OjAZERw==/lib/arm64/libnative-lib.so (Java_com_boyaa_v8wrapper_MainActivity_nativeInit+72): Routine Java_com_boyaa_v8wrapper_MainActivity_nativeInit at F:\ubuntu\share\V8Android\app\src\main\cpp/native-lib.cpp:165
Stack frame         #07 pc 00000000000092b8  /data/app/com.boyaa.v8wrapper-gc82kSUIyk_jPb6OjAZERw==/oat/arm64/base.odex (offset 0x9000)

AddressSanitize

请参见AddressSanitize

Native Tracing

请参见Native Tracing